//
//  NSData+YC.m
//  YCSchool
//
//  Created by yanglinxia on 16/4/26.
//  Copyright © 2016年 yanglinxia. All rights reserved.
//  二进制

#import "NSData+YC.h"

@implementation NSData (YC)


- (NSData *)yc_decryptWithKey:(NSString *)key iv:(NSString *)iv
{
    return [self yc_crypto:kCCDecrypt key:key.UTF8String iv:iv.UTF8String];
}

- (NSData *)yc_encryptWithKey:(NSString *)key iv:(NSString *)iv
{
    return [self yc_crypto:kCCEncrypt key:key.UTF8String iv:iv.UTF8String];
}

- (NSData *)yc_crypto:(CCOperation)operation  key:(const char *)key iv:(const char *)iv
{
    if(!self.length)
    {
        return nil;
    }
    
    //密文长度
    size_t size = self.length + kCCKeySizeDES;
    
    Byte *buffer = (Byte *)malloc(size * sizeof(Byte));
    
    //结果的长度
    size_t numBytes = 0;
    
    //CCCrypt函数 加密/解密
    CCCryptorStatus cryptStatus = CCCrypt(
                                          operation,//  加密/解密
                                          kCCAlgorithmDES,//  加密根据哪标准（des3desaes）
                                          kCCOptionPKCS7Padding,//  选项组密码算(des:每块组加密  3DES：每块组加三同密)
                                          key,//密钥    加密解密密钥必须致
                                          kCCKeySizeDES,//  DES 密钥（kCCKeySizeDES=8）
                                          iv,//  选初始矢量
                                          self.bytes,// 数据存储单元
                                          self.length,// 数据
                                          buffer,// 用于返数据
                                          size,
                                          &numBytes
                                          );
    
    
    NSData *result = nil;
    
    if(cryptStatus == kCCSuccess)
    {
        result = [NSData dataWithBytes:buffer length:numBytes];
    }
    
    //释放指针
    free(buffer);
    
    return result;
}

- (NSData *)yc_crypto3des:(CCOperation)operation  key:(const char *)key iv:(const char *)iv
{
    if(!self.length)
    {
        return nil;
    }
    
    //密文长度
    size_t size = self.length + kCCKeySize3DES;
    
    Byte *buffer = (Byte *)malloc(size * sizeof(Byte));
    
    //结果的长度
    size_t numBytes = 0;
    
    CCCryptorStatus cryptStatus = CCCrypt(
                                          operation,
                                          kCCAlgorithm3DES,
                                          kCCOptionPKCS7Padding,
                                          key,
                                          kCCKeySize3DES,
                                          iv,
                                          self.bytes,
                                          self.length,
                                          buffer,
                                          size,
                                          &numBytes
                                          );
    
    
    NSData *result = nil;
    
    if(cryptStatus == kCCSuccess)
    {
        result = [NSData dataWithBytes:buffer length:numBytes];
    }
    
    //释放指针
    free(buffer);
    
    return result;
}

- (NSString *)yc_hexStringOfData
{
    Byte *bytes = (Byte *)[self bytes];
    NSMutableString *hexString = [[NSMutableString alloc] init];
    for(int i = 0;i < [self length];i++)
    {
        NSString *newHexStr = [NSString stringWithFormat:@"%x",bytes[i]&0xff];///16进制数
        if(1 == [newHexStr length])
        {
            [hexString appendFormat:@"0%@",newHexStr];
        }
        else
        {
            [hexString appendFormat:@"%@",newHexStr];
        }
    }
    return [hexString copy];
}

- (NSData *)yc_RSADecryptWithPublicKeyRef:(SecKeyRef)keyRef
{
    if(!keyRef)
    {
        return nil;
    }
    
    const uint8_t *srcbuf = (const uint8_t *)[self bytes];
    
    size_t srclen = (size_t)self.length;
    
    size_t outlen = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t);
    if(srclen != outlen)
    {
        CFRelease(keyRef);
        return nil;
    }
    UInt8 *outbuf = malloc(outlen);
    
    OSStatus status = noErr;
    status = SecKeyDecrypt(keyRef,
                           kSecPaddingNone,
                           srcbuf,
                           srclen,
                           outbuf,
                           &outlen
                           );
    NSData *result = nil;
    if (status != 0)
    {
        YCLog(@"SecKeyDecrypt fail. Error Code: %d", (int)status);
    }
    else
    {
        //the actual decrypted data is in the middle, locate it!
        int idxFirstZero = -1;
        int idxNextZero = (int)outlen;
        for ( int i = 0; i < outlen; i++ ) {
            if ( outbuf[i] == 0 ) {
                if ( idxFirstZero < 0 ) {
                    idxFirstZero = i;
                } else {
                    idxNextZero = i;
                    break;
                }
            }
        }
        
        result = [NSData dataWithBytes:&outbuf[idxFirstZero+1] length:idxNextZero-idxFirstZero-1];
    }
    
    free(outbuf);
    CFRelease(keyRef);
    return result;
}

- (NSData *)yc_RSAEncryptWithPublicKeyRef:(SecKeyRef)keyRef
{
    if(!keyRef)
    {
        return nil;
    }
    
    const uint8_t *srcbuf = (const uint8_t *)[self bytes];
    size_t srclen = (size_t)self.length;
    
    size_t outlen = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t);
    if(srclen > outlen - 11){
        CFRelease(keyRef);
        return nil;
    }
    void *outbuf = malloc(outlen);
    
    OSStatus status = noErr;
    status = SecKeyEncrypt(keyRef,
                           kSecPaddingNone,
                           srcbuf,
                           srclen,
                           outbuf,
                           &outlen
                           );
    NSData *ret = nil;
    if (status != 0)
    {
        YCLog(@"SecKeyEncrypt fail. Error Code: %d", (int)status);
    }
    else
    {
        ret = [NSData dataWithBytes:outbuf length:outlen];
    }
    free(outbuf);
    CFRelease(keyRef);
    return ret;
}

- (NSData *)yc_AES256DecryptWithKey:(NSString *)key
{
    NSUInteger dataLength = [self length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    
    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding| kCCOptionECBMode,
                                          [key UTF8String],
                                          kCCKeySizeAES256,
                                          NULL,
                                          [self bytes],
                                          dataLength,
                                          buffer,
                                          bufferSize,
                                          &numBytesDecrypted);
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    }
    free(buffer);
    return nil;
}

- (NSData *)yc_AES256EncryptWithKey:(NSString *)key
{
    NSUInteger dataLength = [self length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    
    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding | kCCOptionECBMode,
                                          [key UTF8String],
                                          kCCKeySizeAES256,
                                          NULL,
                                          [self bytes],
                                          dataLength,
                                          buffer,
                                          bufferSize,
                                          &numBytesEncrypted);
    
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }
    free(buffer);
    return nil;
}

- (NSString *)yc_utf8String
{
    return [[NSString alloc] initWithData:self encoding:NSUTF8StringEncoding];
}


@end
